package pl.koszolko.documentclustering.dao;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.log4j.Logger;

import pl.koszolko.documentclustering.cluster.VectorCreator;
import pl.koszolko.documentclustering.dao.imp.JdbcAuthorDao;
import pl.koszolko.documentclustering.dao.imp.JdbcAuthorshipDao;
import pl.koszolko.documentclustering.dao.imp.JdbcDocumentDao;
import pl.koszolko.documentclustering.dao.imp.JdbcQuotationDao;
import pl.koszolko.documentclustering.dao.utils.DataBaseConnectionManager;

public class Factory {
	private static final String MIN_NUMBER_OF_REFERENCES = "references";
	private static final String MIN_NUMBER_OF_CITED_BY = "citedBy";
	private static final String PROPERTIES_FILE = "filterConfig.properties";

	private static Logger logger = Logger.getLogger(Factory.class);
	
	private DataBaseConnectionManager connectionManager;
	private DocumentDao documentDao;
	private QuotationDao quotationDao;
	private AuthorDao	authorDao;
	private AuthorshipDao authorshipDao;
	private int minNumberOfReferences;
	private int minNumberOfCitedBy;
	
	public Factory(DataBaseConnectionManager connectionManager) {
		this.connectionManager = connectionManager;
		createDaoObject();
		initFilterCondition();
	}
	
	private void initFilterCondition() {
		Properties properties;
		try {
			properties = loadProperties();
			minNumberOfReferences = Integer.parseInt(properties.getProperty(MIN_NUMBER_OF_REFERENCES));
			minNumberOfCitedBy = Integer.parseInt(properties.getProperty(MIN_NUMBER_OF_CITED_BY));
		} catch(Exception e) {
			logger.info("Blad podczas pobierania ustawien filtrowania");
			logger.debug(e);
			logger.info("Zostana ustawione domyslne wartosci: minNumberOfReferences = 2; minNumberOfCitedBy = 2");
			minNumberOfReferences = 2;
			minNumberOfCitedBy = 2;
		}
	}

	private Properties loadProperties() throws FileNotFoundException, IOException {
		Properties properties = new Properties();
		
		properties.load(new FileInputStream("config" + File.separator + PROPERTIES_FILE));

		return properties;
	}

	private void createDaoObject() {
		documentDao = new JdbcDocumentDao(connectionManager);
		quotationDao = new JdbcQuotationDao(connectionManager);
		authorDao = new JdbcAuthorDao(connectionManager);
		authorshipDao = new JdbcAuthorshipDao(connectionManager);
	}

	/**
	 * Pobiera wyszystkie artykuly z bazy danych.
	 * Odfiltrowuje artykuly, ktore nie nadaja sie do grupowania
	 * @return
	 */
	public List<Document> getAllDocuments() {		
		//wszystkie dokumenty w map
		List<Document> tmpDocuments = documentDao.findAll();
		Map<Long, Document> tmpDocumentsMap = new HashMap<Long, Document>();
		for(Document doc : tmpDocuments) {
			tmpDocumentsMap.put(doc.getId(), doc);
		}
		
		//autorzy
		List<Author> tmpAuthors = authorDao.findAll();
		Map<Long, Author> tmpAuthorsMap = new HashMap<Long,  Author>();
		for(Author aut : tmpAuthors) {
			tmpAuthorsMap.put(aut.getId(), aut);
		}
		List<Authorship> tmpAuthorships = authorshipDao.findAll();
		
		for(Authorship authorship : tmpAuthorships) {
			Document doc = tmpDocumentsMap.get(authorship.getDocumentId());
			if(doc != null) {
				Author aut = tmpAuthorsMap.get(authorship.getAuthorId());
				if(aut != null) {
					doc.addAuthor(aut);
				}
			}
		}
		
		//cytowania
		List<Quotation> tmpQuotations = quotationDao.findAll();
		//uzupelnieni cytowan
		Long lastIdQuotation = null;
		Document tmpDoc = null;
		Document citedBy = null;
		for(Quotation q : tmpQuotations) {
			if(lastIdQuotation == null) {//pierwszy obiek petli
				lastIdQuotation = q.getDocumentId();
				tmpDoc = tmpDocumentsMap.get(lastIdQuotation);
			}
			
			//cytawanie caly czas tego samego dokumentu
			if(lastIdQuotation == q.getDocumentId()) {	
				citedBy = tmpDocumentsMap.get(q.getDocumentCitedId());
				tmpDoc.addReference(citedBy);
				citedBy.addCitedBy(tmpDoc);
			} else {
				lastIdQuotation = q.getDocumentId();
				tmpDoc = tmpDocumentsMap.get(lastIdQuotation);
				citedBy = tmpDocumentsMap.get(q.getDocumentCitedId());
				tmpDoc.addReference(citedBy);
				citedBy.addCitedBy(tmpDoc);
			}
		}
		
		//filtruj wyniki
		List<Document> documents = new ArrayList<Document>();
		for(Document d : tmpDocumentsMap.values()) {
			if(d.getAbstractText() != null && (d.getReferences().size() >= minNumberOfReferences && d.getCitedBy().size() >= minNumberOfCitedBy) && d.getDocumentClass()!=null) {
				documents.add(d);
			}
		}
		return documents;
	}
	
	public List<DocumentAbstractVector> getDocumentForAbstractClustering() {
		List<DocumentAbstractVector> documents = new ArrayList<DocumentAbstractVector>();
		List<Document> allDocuments = getAllDocuments();
		
		for(Document d : allDocuments) {
			if(d.getAbstractText() != null && !d.getAbstractText().isEmpty()) {
				DocumentAbstractVector documentAbstractVector = new DocumentAbstractVector();
				documentAbstractVector.setTitle(d.getTitle());
				documentAbstractVector.setId(d.getId());
				documentAbstractVector.setAbstractTextVector(VectorCreator.createVectorRepresentation(d.getAbstractText()));
				documents.add(documentAbstractVector);
			}
		}
		
		return documents;
	}

	public void setConnectionManager(DataBaseConnectionManager connectionManager) {
		this.connectionManager = connectionManager;
	}

	public DataBaseConnectionManager getConnectionManager() {
		return connectionManager;
	}
}
